#ifndef __M_MATCHER_H__
#define __M_MATCHER_H__

#include "util.hpp"
#include "online.hpp"
#include "db.hpp"
#include "room.hpp"
#include <list>
#include <mutex>
#include <condition_variable>

// 匹配队列模板类：优化线程安全与接口健壮性
template <class T>
class match_queue {
private:
    std::list<T> _list;               // 存储匹配对象（链表支持中间删除）
    mutable std::mutex _mutex;        // mutable允许const方法加锁，保证线程安全
    std::condition_variable _cond;    // 阻塞消费者线程（队列<2人时等待）

public:
    
    size_t size() const {  
        std::unique_lock<std::mutex> lock(_mutex);
        return _list.size(); 
    }

    bool empty() const {
        std::unique_lock<std::mutex> lock(_mutex);
        return _list.empty();
    }

   
    // 返回值：true=被唤醒，false=超时
    bool wait_for(const std::chrono::milliseconds& timeout = std::chrono::seconds(30)) {
        std::unique_lock<std::mutex> lock(_mutex);
        return _cond.wait_for(lock, timeout) == std::cv_status::no_timeout;
    }
  
    void push(const T& data) {
        std::unique_lock<std::mutex> lock(_mutex);
        _list.push_back(data);
        _cond.notify_all();  // 唤醒所有等待线程（避免单线程唤醒丢失）
    }

   
    bool pop(T& data) {
        std::unique_lock<std::mutex> lock(_mutex);
        if (_list.empty()) {
            return false;  // 队空：无数据可出
        }
        data = _list.front();
        _list.pop_front();
        return true;
    }

   
    void remove(const T& data) {
        std::unique_lock<std::mutex> lock(_mutex);
        _list.remove(data);
    }

  //清空队列（用于析构/紧急停止时释放资源，避免内存泄漏）
    void clear() {
        std::unique_lock<std::mutex> lock(_mutex);
        _list.clear();
    }
};

class matcher {
private:
    // 三个等级匹配队列（保留原分级逻辑）
    match_queue<uint64_t> _q_normal;  // 普通玩家（<2000分）
    match_queue<uint64_t> _q_high;    // 高手玩家（2000≤score<3000）
    match_queue<uint64_t> _q_super;   // 大神玩家（≥3000分）

    // 匹配处理线程（新增线程安全退出机制）
    std::thread _th_normal;
    std::thread _th_high;
    std::thread _th_super;

    // 外部依赖模块（补充空指针检查，避免崩溃）
    room_manager* _rm;
    user_table* _ut;
    online_manager* _om;
    //线程安全的运行标志
    std::atomic<bool> _running{true};
    // 匹配超时时间（5分钟未匹配成功自动重置，避免玩家长时间等待）
    static constexpr auto MATCH_TIMEOUT = std::chrono::minutes(5);

private:
    /**
      mq：目标匹配队列
      queue_tag：队列标识（便于日志区分普通/高手/大神队列）
     */
    void handle_match(match_queue<uint64_t>& mq, const std::string& queue_tag) {
        while (_running) {
            // 1. 等待队列≥2人（带超时，避免永久阻塞）
            auto start_time = std::chrono::steady_clock::now();
            while (mq.size() < 2 && _running) {
                // 检查匹配超时：避免玩家长时间卡在匹配中
                auto elapsed = std::chrono::steady_clock::now() - start_time;
                if (elapsed >= MATCH_TIMEOUT) {
                    DLOG("[%s] 匹配超时（超过5分钟），重置等待计时", queue_tag.c_str());
                    start_time = std::chrono::steady_clock::now();
                }
                // 30秒超时等待：避免条件变量虚假唤醒导致无限阻塞
                if (!mq.wait_for(std::chrono::seconds(30))) {
                    continue;
                }
            }

            // 2. 检查是否需要退出（如程序关闭）
            if (!_running) break;

            // 3. 出队两个玩家
            uint64_t uid1 = 0, uid2 = 0;
            bool ret = mq.pop(uid1);
            if (!ret) {
                DLOG("[%s] 玩家1出队失败，跳过本次匹配", queue_tag.c_str());
                continue;
            }

            ret = mq.pop(uid2);
            if (!ret) {
                DLOG("[%s] 玩家2出队失败，将玩家1（%lu）重新入队", queue_tag.c_str(), uid1);
                this->add(uid1);  // 放回玩家1，避免丢失
                continue;
            }

            // 4. 双重校验玩家在线状态（避免匹配过程中离线）
            if (!_om || !_om->is_in_game_hall(uid1)) {
                DLOG("[%s] 玩家1（%lu）已离线/不在大厅，将玩家2（%lu）重新入队", queue_tag.c_str(), uid1, uid2);
                this->add(uid2);
                continue;
            }
            if (!_om || !_om->is_in_game_hall(uid2)) {
                DLOG("[%s] 玩家2（%lu）已离线/不在大厅，将玩家1（%lu）重新入队", queue_tag.c_str(), uid2, uid1);
                this->add(uid1);
                continue;
            }

            
            wsserver_t::connection_ptr conn1 = _om->get_conn_from_hall(uid1);
            wsserver_t::connection_ptr conn2 = _om->get_conn_from_hall(uid2);
            if (!conn1) {
                DLOG("[%s] 玩家1（%lu）连接无效，将玩家2（%lu）重新入队", queue_tag.c_str(), uid1, uid2);
                this->add(uid2);
                continue;
            }
            if (!conn2) {
                DLOG("[%s] 玩家2（%lu）连接无效，将玩家1（%lu）重新入队", queue_tag.c_str(), uid2, uid1);
                this->add(uid1);
                continue;
            }

            // 5. 创建房间（优化：检查room_manager有效性，避免空指针崩溃）
            if (!_rm) {
                DLOG("[%s] 房间管理器未初始化，将玩家1（%lu）、玩家2（%lu）重新入队", queue_tag.c_str(), uid1, uid2);
                this->add(uid1);
                this->add(uid2);
                continue;
            }
            room_ptr rp = _rm->create_room(uid1, uid2);
            if (!rp) {
                DLOG("[%s] 创建房间失败，将玩家1（%lu）、玩家2（%lu）重新入队", queue_tag.c_str(), uid1, uid2);
                this->add(uid1);
                this->add(uid2);
                continue;
            }

            // 6. 响应玩家
            Json::Value resp;
            resp["optype"] = "match_success";
            resp["result"] = true;
            resp["room_id"] = Json::UInt64(rp->id());  
            resp["white_uid"] = Json::UInt64(uid1);    
            resp["black_uid"] = Json::UInt64(uid2);    

            std::string body;
            if (json_util::serialize(resp, body)) {
             
                try {
                    conn1->send(body);
                    conn2->send(body);
                    DLOG("[%s] 匹配成功：房间ID=%lu，白棋=%lu，黑棋=%lu", queue_tag.c_str(), rp->id(), uid1, uid2);
                } catch (const std::exception& e) {
                    DLOG("[%s] 发送匹配成功消息失败：%s，回滚房间并重新入队", queue_tag.c_str(), e.what());
                    _rm->remove_room(rp->id());  // 回滚：删除无效房间
                    this->add(uid1);
                    this->add(uid2);
                }
            } else {
                DLOG("[%s] JSON序列化失败，将玩家1（%lu）、玩家2（%lu）重新入队", queue_tag.c_str(), uid1, uid2);
                _rm->remove_room(rp->id());  // 回滚：删除无效房间
                this->add(uid1);
                this->add(uid2);
            }
        }
        DLOG("[%s] 匹配线程已退出", queue_tag.c_str());
    }


    void th_normal_entry() { handle_match(_q_normal, "普通玩家队列"); }
    void th_high_entry() { handle_match(_q_high, "高手玩家队列"); }
    void th_super_entry() { handle_match(_q_super, "大神玩家队列"); }

public:
    
    matcher(room_manager* rm, user_table* ut, online_manager* om)
        : _rm(rm), _ut(ut), _om(om),
          _th_normal(std::thread(&matcher::th_normal_entry, this)),
          _th_high(std::thread(&matcher::th_high_entry, this)),
          _th_super(std::thread(&matcher::th_super_entry, this)) {
        // 检查线程是否创建成功
        if (!_th_normal.joinable()) {
            throw std::runtime_error("普通玩家匹配线程创建失败");
        }
        if (!_th_high.joinable()) {
            throw std::runtime_error("高手玩家匹配线程创建失败");
        }
        if (!_th_super.joinable()) {
            throw std::runtime_error("大神玩家匹配线程创建失败");
        }
        DLOG("游戏匹配模块初始化完毕....");
    }

    
    ~matcher() {
        _running = false;  // 设置退出标志
        // 唤醒所有阻塞线程，清空队列
        _q_normal.clear();
        _q_high.clear();
        _q_super.clear();
        // 等待线程退出（避免僵尸线程）
        if (_th_normal.joinable()) {
            _th_normal.join();
        }
        if (_th_high.joinable()) {
            _th_high.join();
        }
        if (_th_super.joinable()) {
            _th_super.join();
        }
        DLOG("游戏匹配模块已销毁");
    }

    // 添加玩家到匹配队列（补充参数校验，避免无效玩家入队）
    bool add(uint64_t uid) {
        // 校验外部依赖有效性
        if (!_ut || !_om) {
            DLOG("用户数据库/在线管理器未初始化，添加玩家（%lu）失败", uid);
            return false;
        }
        // 校验玩家是否在大厅（避免离线玩家入队）
        if (!_om->is_in_game_hall(uid)) {
            DLOG("玩家（%lu）不在游戏大厅，添加匹配失败", uid);
            return false;
        }

        // 获取玩家分数
        Json::Value user;
        bool ret = _ut->select_by_id(uid, user);
        if (!ret) {
            DLOG("获取玩家（%lu）信息失败，添加匹配失败", uid);
            return false;
        }
        int score = user["score"].asInt();

        // 分级入队
        if (score < 2000) {
            _q_normal.push(uid);
        } else if (score < 3000) {  // 已满足score≥2000，简化条件
            _q_high.push(uid);
        } else {
            _q_super.push(uid);
        }

        DLOG("玩家（%lu，分数：%d）已加入匹配队列", uid, score);
        return true;
    }

    // 从匹配队列移除玩家（补充参数校验，避免无效操作）
    bool del(uint64_t uid) {
        if (!_ut) {
            DLOG("用户数据库未初始化，移除玩家（%lu）匹配失败", uid);
            return false;
        }

        Json::Value user;
        bool ret = _ut->select_by_id(uid, user);
        if (!ret) {
            DLOG("获取玩家（%lu）信息失败，移除匹配失败", uid);
            return false;
        }
        int score = user["score"].asInt();

        // 分级移除
        if (score < 2000) {
            _q_normal.remove(uid);
        } else if (score < 3000) {
            _q_high.remove(uid);
        } else {
            _q_super.remove(uid);
        }

        DLOG("玩家（%lu）已取消匹配", uid);
        return true;
    }
};

#endif
